package main

import (
	"context"
	"errors"
	"fmt"
	"io"
	"kitc/pub"
	"os"
	"sync"
	"time"

	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/sd"
	"github.com/go-kit/kit/sd/lb"
	"github.com/go-kit/kit/sd/zk"
	"google.golang.org/grpc"
)

func reqF(serviceAddress string) (endpoint.Endpoint, io.Closer, error) {
	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
		req := request.([]interface{})
		ag := req[0].(*BookAgent)
		_ = ag

		// fmt.Println("request", serviceAddress)
		// time.Sleep(time.Duration(500) * time.Millisecond)
		conn, e := ag.Get(serviceAddress)
		if e != nil {
			return nil, e
		}
		switch req[1].(string) {
		case "GetBookInfo":
			r, e := conn.GetBookInfo(context.Background(), req[2].(*pub.BookInfoParams))
			// for e != nil {
			// 	conn, _ = ag.Next(conn)
			// 	r, e = conn.GetBookInfo(context.Background(), req[2].(*pub.BookInfoParams))
			// }
			return r, e
		default:
			break
		}

		return nil, nil
	}, nil, nil
}

type BookAgent struct {
	bep  endpoint.Endpoint
	ctx  context.Context
	svrs []*SvrItem
	lk   sync.Mutex
}

func (self *BookAgent) Get(addr string) (pub.BookServiceClient, error) {
	// self.lk.Lock()
	// defer self.lk.Unlock()
	for _, v := range self.svrs {
		if v.addr == addr {
			return v.con, nil
		}
	}
	conn, err := grpc.Dial(addr, grpc.WithInsecure())

	if err != nil {
		return nil, err
	}
	cli := pub.NewBookServiceClient(conn)
	self.svrs = append(self.svrs, &SvrItem{
		addr: addr,
		idx:  len(self.svrs),
		con:  cli,
	})

	return cli, nil

}
func (self *BookAgent) Next(con pub.BookServiceClient) (pub.BookServiceClient, error) {
	// self.lk.Lock()
	// defer self.lk.Unlock()
	for idx, v := range self.svrs {
		if v.con == con {
			return self.svrs[(idx+1)%len(self.svrs)].con, nil
		}
	}
	return nil, errors.New("error")
}

type SvrItem struct {
	con  pub.BookServiceClient
	addr string
	idx  int
}

func NewBookAgent(bep endpoint.Endpoint, ctx context.Context) *BookAgent {
	return &BookAgent{
		bep:  bep,
		ctx:  ctx,
		svrs: make([]*SvrItem, 0),
	}
}
func (self *BookAgent) GetBookInfo() (*pub.BookInfo, error) {

	resp, e := self.bep(self.ctx, []interface{}{self, "GetBookInfo", &pub.BookInfoParams{BookId: 1}})
	if e != nil {
		//fmt.Println(e)
		return nil, e
	}
	return resp.(*pub.BookInfo), nil
}

func main() {

	// lb

	l := log.NewLogfmtLogger(os.Stdout)
	c, _ := zk.NewClient([]string{"192.168.10.144:2181"}, l)
	inst, _ := zk.NewInstancer(c, "/bsvr/bsvr1", l)
	ep := sd.NewEndpointer(inst, reqF, l)
	nlb := lb.NewRoundRobin(ep)

	bep := lb.Retry(3, time.Duration(3)*time.Second, nlb)

	fff := func(id int) {
		tms2 := time.Now()
		ec2 := 0

		l := log.NewLogfmtLogger(os.Stdout)
		c, _ := zk.NewClient([]string{"192.168.10.144:2181"}, l)
		inst, _ := zk.NewInstancer(c, "/bsvr/bsvr1", l)
		ep := sd.NewEndpointer(inst, reqF, l)
		nlb := lb.NewRoundRobin(ep)

		bep := lb.Retry(3, time.Duration(3)*time.Second, nlb)

		bcc := NewBookAgent(bep, context.Background())
		for i := 0; i < 10000000; i++ {
			_, e := bcc.GetBookInfo()
			if e != nil {
				ec2++
			}
			if i%10000 == 0 {
				n := time.Now()

				fmt.Printf("%d\t%f\t%d\n", id, float64(i)/n.Sub(tms2).Seconds(), ec2)
			}
		}

	}
	go fff(2)
	go fff(3)
	go fff(4)

	be := NewBookAgent(bep, context.Background())
	tms2 := time.Now()
	errcnt := 0
	for i := 0; i < 10000000; i++ {
		bkinfo, e := be.GetBookInfo()
		if e != nil {
			errcnt++
			//fmt.Println(e, errcnt)
			//continue
		}
		//time.Sleep(time.Duration(3) * time.Second)
		_ = bkinfo
		if i%10000 == 0 {
			n := time.Now()

			fmt.Printf("%d\t%f\t%d\n", 1, float64(i)/n.Sub(tms2).Seconds(), errcnt)
		}
	}

	//_ = bkinfo

	/*
		serviceAddress := "127.0.0.1:50502"

		conn, err := grpc.Dial(serviceAddress, grpc.WithInsecure())
		if err != nil {
			panic("connect error")
		}
		defer conn.Close()
		bookClient := pub.NewBookServiceClient(conn)

		tms := time.Now()
		ec := 0
		fff := func(id int) {
			tms2 := time.Now()
			ec2 := 0
			for i := 0; i < 10000000; i++ {
				_, e := bookClient.GetBookList(context.Background(), &pub.BookListParams{Page: 1, Limit: 10})
				if e != nil {
					ec2++
				}
				if i%10000 == 0 {
					n := time.Now()

					fmt.Printf("%d\t%f\t%d\n", id, float64(i)/n.Sub(tms2).Seconds(), ec2)
				}
			}

		}
		_ = fff
		go fff(2)
		go fff(3)
		go fff(4)
		for i := 0; i < 10000000; i++ {
			_, e := bookClient.GetBookInfo(context.Background(), &pub.BookInfoParams{BookId: 1})
			if e != nil {
				ec++
				fmt.Println(e)
			}
			if i%10000 == 0 {
				n := time.Now()

				fmt.Printf("1\t%f\t%d\n", float64(i)/n.Sub(tms).Seconds(), ec)
			}
		}
	*/
}
